﻿using NDK.Communacation;
using NDK.Motion.BLL;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Windows.Forms;

namespace NDK.Module.Model.Quebec
{
    public class KeyencePPG
    {
        public ECommunacation Socket = null;
        public int DecimalFactor = -1;
        //GT/GT2/IL/IG/IB/SK：037
        public string DeviceNo = "037";
        public static List<string> ReceiveStrList = new List<string>();
        public bool Init(string IP, int Port)
        {
            try
            {
                string hostServerCom = EComManageer.CreateECom(CommunicationModel.TcpClient);
                Socket = EComManageer.GetECommunacation(hostServerCom);
                Socket.RemoteIP = IP;
                Socket.RemotePort = Port;
                Socket.ReceiveString += ReceiveString;
                EComManageer.Connect(hostServerCom);
                Thread.Sleep(1000);
                if (Socket.IsConnected)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch (Exception)
            {
                return false;
            }
        }

        public void ReceiveString(string str)
        {
            if (ReceiveStrList.Count > 1000)
                ReceiveStrList.RemoveRange(0, 100);
            ReceiveStrList.Add(str);
            //Common.AppendUiLog.Log($"Keyence DL-EN1 接收到:{str}", LogType.Alert);
        }

        public void SendStr(string cmd)
        {
            Socket.SendStr(cmd + Environment.NewLine);
        }
        static readonly object obj = new object();
        public Rtn FindReturnFit(string cmd, int timeout = 1000)
        {
            lock (obj)
            {
                Rtn rtn = new Rtn();
                rtn.Code = RtnCode.Default;
                var findItem = "";
                Stopwatch sw = new Stopwatch();
                sw.Start();
                do
                {
                    if (ReceiveStrList.Count > 0)
                    {

                        try
                        {
                            foreach (string str in ReceiveStrList)
                            {
                                if (str.Contains(cmd))
                                {
                                    findItem = ReceiveStrList.FindLast(x => x.Contains(cmd));
                                    break;
                                }
                            }
                        }
                        catch
                        {
                        }

                        if (findItem != "")
                        {
                            findItem.Replace("\r\n", "");
                            rtn.Msg = findItem;
                            rtn.Code = RtnCode.OK;
                            ReceiveStrList.Remove(findItem);
                            break;
                        }
                    }
                    else
                    {
                        Thread.Sleep(10);
                    }
                } while (sw.ElapsedMilliseconds < timeout);
                if (rtn.Code == RtnCode.Default)
                {
                    rtn.Code = RtnCode.NoReturn;
                    rtn.Msg = RtnCode.NoReturn.ToString();
                }

                return rtn;
            }
        }

        public Rtn CheckDecimalFactor(string ID = "01")
        {
            Rtn rtn = new Rtn();
            if (DecimalFactor < 0)
            {
                rtn = ReadDecimal(ID);
                if (rtn.Code != RtnCode.OK)
                {
                    return rtn;
                }
            }
            else
            {
                rtn.Code = RtnCode.OK;
            }
            return rtn;
        }
        public Rtn GetRtnValue(string rtnStr, string ID = "01")
        {
            Rtn rtn = new Rtn();
            var signStr = rtnStr.Substring(0, 1);
            var valueStr = rtnStr.Substring(1, rtnStr.Length - 2);
            var valueNoDecimal = int.Parse(valueStr);

            rtn = CheckDecimalFactor(ID);
            if (rtn.Code != RtnCode.OK)
                return rtn;
            double valueNoSign = Math.Round(valueNoDecimal / (double)DecimalFactor, 4);
            if (signStr.Equals("-"))
                rtn.Value = valueNoSign * -1;
            else
                rtn.Value = valueNoSign;
            rtn.Code = RtnCode.OK;
            return rtn;
        }

        public Rtn GetSendValue(double value, string ID = "01")
        {
            Rtn rtn = new Rtn();
            rtn = CheckDecimalFactor(ID);
            if (rtn.Code != RtnCode.OK)
                return rtn;
            string sendStr = "";
            if (value > 0)
            {
                sendStr = (value * DecimalFactor).ToString().PadLeft(9, '0');
                sendStr.Insert(0, "+");
            }
            else
            {
                sendStr = (value * -1 * DecimalFactor).ToString().PadLeft(9, '0');
                sendStr.Insert(0, "-");
            }
            rtn.Code = RtnCode.OK;
            rtn.Msg = sendStr;
            return rtn;
        }

        public Rtn GetRtn(string rtnKey)
        {
            Rtn rtn = new Rtn();
            if (string.IsNullOrEmpty(rtnKey))
                return rtn;
            try
            {
                rtn = FindReturnFit(rtnKey);
            }
            catch (Exception)
            {
                Thread.Sleep(100);
                rtn = FindReturnFit(rtnKey);
            }

            if (rtn.Code != RtnCode.OK)
            {
                return rtn;
            }
            var value = rtn.Msg.Replace(rtnKey + ",", "");
            rtn = GetRtnValue(value);
            return rtn;
        }
        /// <summary>
        /// 读取小数位
        /// </summary>
        public Rtn ReadDecimal(string ID = "01")
        {
            Rtn rtn = new Rtn();
            //指令：FR,ID编号,数据编号
            //指令示例：FR,01,037
            string cmd = $"FR,{ID},{DeviceNo}";
            string rtnKey = cmd;
            SendStr(cmd);
            rtn = FindReturnFit(rtnKey);
            if (rtn.Code != RtnCode.OK)
            {
                DecimalFactor = -1;
                return rtn;
            }

            var findRtn = rtn.Msg;
            findRtn = findRtn.Replace(cmd + ",", "");
            var valueStr = findRtn.Substring(1, rtnKey.Length);
            var value = int.Parse(valueStr);
            DecimalFactor = int.Parse("1".PadRight(value, '0'));

            rtn.Value = value;
            rtn.Code = RtnCode.OK;
            return rtn;
        }

        /// <summary>
        /// 读取所有传感器放大器的当前值
        /// </summary>
        public Rtn ReadAll()
        {
            Rtn rtn = new Rtn();
            //指令：FR,ID编号,数据编号
            //指令示例：FR,01,037
            string cmd = $"M0";
            string rtnKey = cmd;
            SendStr(cmd);
            rtn = GetRtn(rtnKey);
            return rtn;
        }

        /// <summary>
        /// 读取所有传感器放大器的当前值
        /// </summary>
        public Rtn ReadCH(string ID = "01")
        {
            Rtn rtn = new Rtn();
            //指令：SR,ID编号,数据编号
            //指令示例：SR,01,037
            string cmd = $"SR,{ID},{DeviceNo}";
            string rtnKey = cmd;
            SendStr(cmd);
            rtn = GetRtn(rtnKey);

            return rtn;
        }

        public double Read(string ID)
        {
        Line:
            try
            {
                List<double> list = new List<double>();
                for (int i = 0; i < 8; i++)
                {
                    var rtn = Machine.PPG.ReadCH(ID);
                    if (rtn.Code == RtnCode.OK)
                        list.Add(rtn.Value);
                }

                if (list.Count > 0)
                {
                    double Value = 9999;
                    if (list.Count >= 3)
                    {
                        list.Remove(list.Max());
                        list.Remove(list.Min());

                        Value = Math.Round(list.Average(), 4);
                    }
                    else
                    {
                        Value = Math.Round(list.Average(), 4);
                    }
                    return Value;
                }
                else
                {
                    Socket.DisConnect();
                    Socket = null;
                    Thread.Sleep(200);
                    bool status = Init(Common.PPGIP, 64000);
                    if (!status)
                    {
                        if (MessageBox.Show("PPG控制器异常:\r\n点击确定重连,点击取消忽略", "PPG读取失败", MessageBoxButtons.OKCancel, MessageBoxIcon.Error) == DialogResult.OK)
                        {
                            goto Line;
                        }
                    }
                    else
                        goto Line;
                    return 9999;
                }
            }
            catch
            {
                Socket.DisConnect();
                Socket = null;
                Thread.Sleep(200);
                bool status = Machine.PPG.Init(Common.PPGIP, 64000);
                if (!status)
                {
                    if (MessageBox.Show("PPG控制器异常:\r\n点击确定重连,点击取消忽略", "PPG读取失败", MessageBoxButtons.OKCancel, MessageBoxIcon.Error) == DialogResult.OK)
                    {
                        goto Line;
                    }
                }
                else
                    goto Line;
                return 9999;
            }


        }
        /// <summary>
        /// 对指定编号传感器放大器的当前值做归零操作
        /// 零点写入的数据编号：GT/GT2/IL/IG/IB/SK：001
        /// </summary>
        public bool SetZero(string ID = "01")
        {
            //指令示例：SW,01,001,+000000000
            //SW,01,001,+000000001
            //（注意：逗号必须为半角符号,两条指令必须分开发送）
            Rtn rtn = new Rtn();
            string cmd1 = $"SW,{ID},001,+000000000";
            string cmd2 = $"SW,{ID},001,+000000001";
            string rtnKey = $"SW,{ID},001";
            Socket.SendStr(cmd1 + Environment.NewLine);
            rtn = GetRtn(rtnKey);
            if (rtn.Code != RtnCode.OK)
                return false;
            Socket.SendStr(cmd2 + Environment.NewLine);
            rtn = GetRtn(rtnKey);
            if (rtn.Code != RtnCode.OK)
                return false;
            return true;
        }

        /// <summary>
        /// 对指定编号传感器放大器修改SHIFT值
        /// </summary>
        public bool SetShift(int Shift, string ID = "01")
        {
            Rtn rtn = new Rtn();
            //SHIFT值的数据编号：067
            //指令示例：SW,01,067,+000002000
            rtn = GetSendValue(Shift, ID);
            if (rtn.Code != RtnCode.OK)
                return false;
            string cmd = $"SW,{ID},067,{rtn.Msg}";
            string rtnKey = $"SW,{ID},067";
            SendStr(cmd);
            rtn = GetRtn(rtnKey);
            if (rtn.Code != RtnCode.OK)
                return false;
            return true;
        }

        /// <summary>
        /// 对指定编号传感器放大器修改上限
        /// </summary>
        public bool SetUSL(int USL, string ID = "01")
        {
            //指令示例：SW,01,065,+000002000
            //HI值的数据编号：065
            Rtn rtn = new Rtn();
            rtn = GetSendValue(USL, ID);
            if (rtn.Code != RtnCode.OK)
                return false;
            string cmd = $"SW,{ID},065,{rtn.Msg}";
            string rtnKey = $"SW,{ID},065";
            SendStr(cmd);
            rtn = GetRtn(rtnKey);
            if (rtn.Code != RtnCode.OK)
                return false;
            return true;
        }

        /// <summary>
        /// 对指定编号传感器放大器修改下限
        /// </summary>
        public bool SetLSL(int LSL, string ID = "01")
        {
            //指令示例：SW,01,065,+000002000
            //HI值的数据编号：066
            Rtn rtn = new Rtn();
            rtn = GetSendValue(LSL, ID);
            if (rtn.Code != RtnCode.OK)
                return false;
            string cmd = $"SW,{ID},066,{rtn.Msg}";
            string rtnKey = $"SW,{ID},066";
            SendStr(cmd);
            rtn = GetRtn(rtnKey);
            if (rtn.Code != RtnCode.OK)
                return false;
            return true;
        }

        public Rtn SendCmd(string cmd)
        {
            Rtn rtn = new Rtn();
            var cmdStrs = cmd.Split(',');
            var rtnKey = "";
            switch (cmdStrs.Length)
            {
                case 4:
                    rtnKey = cmd.Remove(cmd.LastIndexOf(','), cmd.Length - 1);
                    break;
                default:
                    rtnKey = cmd;
                    break;
            }
            SendStr(cmd);
            rtn = GetRtn(rtnKey);
            return rtn;
        }

        public class Rtn
        {
            public RtnCode Code { get; set; }
            public string Msg { get; set; }
            public double Value { get; set; }

            public Rtn()
            {
                Code = RtnCode.Default;
                Msg = "";
                Value = -1;
            }
        }

        public enum RtnCode
        {
            Default = -1,
            OK = 0,
            NoReturn = 1,
            NoDecimal = 2,
        }
    }
}
